package jp.co.nes.awssupport.common.utility;

import java.io.IOException;
import java.io.InputStream;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import jp.co.nes.awssupport.common.base.CommonException;
import jp.co.nes.awssupport.common.bean.BaseBean;

/**
 * Yamlユーティリティです。
 */
public class YamlUtil {

    /** ObjectMapper */
    private static ObjectMapper mapper;

    /**
     * 初期化処理です。
     */
    static {
        // ObjectMapperはスレッドセーフ
        mapper = new ObjectMapper(new YAMLFactory());
        mapper.registerModule(new JavaTimeModule());
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.PUBLIC_ONLY);
    }

    /**
     * デフォルトコンストラクタです。<br>
     * 本クラスは生成しません。
     */
    private YamlUtil() {
    }

    /**
     * BeanクラスをYamlバイト配列に変換し、返却します。
     *
     * @param bean 変換するBeanクラスのインスタンス
     * @return 変換結果
     */
    public static <T extends BaseBean> byte[] convertBeanToYamlBytes(T bean) {
        try {
            return mapper.writeValueAsBytes(bean);
        } catch (JsonProcessingException e) {
            throw new CommonException(e);
        }
    }

    /**
     * 入力ストリーム(Yaml)からBeanクラスに変換し、返却します。
     *
     * @param yaml 入力ストリーム(Yaml)
     * @param targetClass 変換するBeanクラスのClassオブジェクト
     * @return 変換結果
     */
    public static <T extends BaseBean> T convertYamlInputStreamToBean(InputStream yaml, Class<T> targetClass) {
        try {
            return mapper.readValue(yaml, targetClass);
        } catch (IOException e) {
            throw new CommonException(e);
        }
    }

    /**
     * Yaml文字列をJson文字列に変換して、返却します。
     *
     * @param yaml Yaml文字列
     * @param isIndentOutput true: 変換後のJson文字列にインデントを付加します、false: 変換後のJson文字列にインデントを付加しません。
     * @return 変換結果
     */
    public static String convertYamlStringToJsonString(String yaml, boolean isIndentOutput) {
        ObjectMapper mapperOfJson = new ObjectMapper();
        mapperOfJson.registerModule(new JavaTimeModule());
        mapperOfJson.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.PUBLIC_ONLY);
        if (isIndentOutput) {
            mapperOfJson.enable(SerializationFeature.INDENT_OUTPUT);
        }
        return convertYamlStringToJsonString(yaml, mapperOfJson);
    }

    /**
     * Yaml文字列をmapperOfJsonを使用して、Json文字列に変換し、返却します。
     *
     * @param yaml Yaml文字列
     * @param mapperOfJson ObjectMapper
     * @return 変換結果
     */
    private static String convertYamlStringToJsonString(String yaml, ObjectMapper mapperOfJson) {
        try {
            Object yamlObject = mapper.readValue(yaml, Object.class);
            return mapperOfJson.writeValueAsString(yamlObject);
        } catch (IOException e) {
            throw new CommonException(e);
        }
    }
}
